﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Abp.Authorization.Users;
using Abp.Domain.Services;
using Abp.IdentityFramework;
using Abp.Runtime.Session;
using Abp.UI;
using SOEI.Solution.Authorization.Roles;
using SOEI.Solution.MultiTenancy;
using SOEI.Solution.Customized;
using static SOEI.Solution.AppCoreConst;
using SOEI.Solution.DomainEntities.Organization.DomainService;
using SOEI.Solution.Integratedes.Organization.DomainService;
using SOEI.Solution.Integratedes.Organization;
using SOEI.Solution.Helper;

namespace SOEI.Solution.Authorization.Users
{
    public class UserRegistrationManager : DomainService
    {
        public IAbpSession AbpSession { get; set; }

        private readonly TenantManager _tenantManager;
        private readonly UserManager _userManager;
        private readonly RoleManager _roleManager;
        private readonly IPasswordHasher<User> _passwordHasher;

        private readonly EconomyOrganiManager _economyOrganiManager;
        private readonly IOEconomyPersonManager _oeconomypersonManager;
        private readonly IOEconomyOrganiManager _oeconomyOrganiManager;

        public UserRegistrationManager(
            TenantManager tenantManager,
            UserManager userManager,
            RoleManager roleManager,
            IPasswordHasher<User> passwordHasher,
             EconomyOrganiManager economyOrganiManager,
            IOEconomyOrganiManager oeconomyOrganiManager,
            IOEconomyPersonManager oeconomypersonManager
            )
        {
            _tenantManager = tenantManager;
            _userManager = userManager;
            _roleManager = roleManager;
            _passwordHasher = passwordHasher;
            _economyOrganiManager = economyOrganiManager;
            _oeconomypersonManager = oeconomypersonManager;
            _oeconomyOrganiManager = oeconomyOrganiManager;

            AbpSession = NullAbpSession.Instance;
        }

        public async Task<User> RegisterAsync(string name, string surname, string emailAddress, string userName, string plainPassword, bool isEmailConfirmed)
        {
            CheckForTenant();

            var tenant = await GetActiveTenantAsync();

            var user = new User
            {
                TenantId = tenant.Id,
                Name = name,
                Surname = surname,
                EmailAddress = emailAddress,
                IsActive = true,
                UserName = userName,
                IsEmailConfirmed = isEmailConfirmed,
                Roles = new List<UserRole>()
            };

            user.SetNormalizedNames();
           
            foreach (var defaultRole in await _roleManager.Roles.Where(r => r.IsDefault).ToListAsync())
            {
                user.Roles.Add(new UserRole(tenant.Id, user.Id, defaultRole.Id));
            }

            await _userManager.InitializeOptionsAsync(tenant.Id);

            CheckErrors(await _userManager.CreateAsync(user, plainPassword));
            await CurrentUnitOfWork.SaveChangesAsync();

            return user;
        }

        private void CheckForTenant()
        {
            if (!AbpSession.TenantId.HasValue)
            {
                throw new InvalidOperationException("Can not register host users!");
            }
        }

        private async Task<Tenant> GetActiveTenantAsync()
        {
            if (!AbpSession.TenantId.HasValue)
            {
                return null;
            }

            return await GetActiveTenantAsync(AbpSession.TenantId.Value);
        }

        private async Task<Tenant> GetActiveTenantAsync(int tenantId)
        {
            var tenant = await _tenantManager.FindByIdAsync(tenantId);
            if (tenant == null)
            {
                throw new UserFriendlyException(L("UnknownTenantId{0}", tenantId));
            }

            if (!tenant.IsActive)
            {
                throw new UserFriendlyException(L("TenantIdIsNotActive{0}", tenantId));
            }

            return tenant;
        }

        protected virtual void CheckErrors(IdentityResult identityResult)
        {
            identityResult.CheckErrors(LocalizationManager);
        }

        #region  ====================================== 用户自定义 ==============================================
        //public virtual string GetSequence(string SequenceName)
        //{ 
        //    this.CurrentUnitOfWork.GetDbContext<User,long>().
        //}

        /// <summary>
        /// 注册经济机构
        /// </summary>
        /// <param name="mobilePhone">要注册机构手机号</param>

        public async Task<User> OrganizationRegister(string PhoneNumber, string plainPassword)
        {
            CheckForTenant();
            var tenant = await GetActiveTenantAsync();

            // 1. 验证手机号
            this.CheckForPhoneNumber(PhoneNumber);
            // 2. 创建一个新的经济机构(包含一个管理员)
            var orgEntity = await this.CreateOrganization(plainPassword);

            // 3.创建一个管理员用户（本地项目管理员）
            var user = new User
            {
                TenantId = tenant.Id,
                PhoneNumber = PhoneNumber,
                IsPhoneNumberConfirmed = false, // 是否验证过电话号码

                IsActive = true,
                Roles = new List<UserRole>(),
                /*OrganizeID = orgEntity.Id,   // 机构编号*/
                UserType = EUserType.Administrator, // 这个用户为机构管理员
                OriginalPassword = plainPassword,      // 原始明文密码，老系统需要用到
                UserName = orgEntity.GLYBH, // 登录名称就是电话号码(登录账号就是原始用户表序列)
                Name = orgEntity.JGMC + "的管理员",
                Surname = "管理员",
                EmailAddress = string.Format("{0}@example.com", PhoneNumber), // 生成一个账号开始的邮箱
                IsEmailConfirmed = false,   // 邮箱没有验证
                OriginalNumber = orgEntity.Id // 对应zhxt中的经济机构编号
            };

            user.SetNormalizedNames();

            // 5. 初始化角色(赋予权限)
            foreach (var defaultRole in await _roleManager.Roles.Where(r => r.Name == AgencyRoleType.AgencyManager).ToListAsync())
            {
                user.Roles.Add(new UserRole(tenant.Id, user.Id, defaultRole.Id));
            }

            await _userManager.InitializeOptionsAsync(tenant.Id);
            CheckErrors(await _userManager.CreateAsync(user, plainPassword));

            await CurrentUnitOfWork.SaveChangesAsync();
            return user;
        }
        #endregion

        #region  ----------------------------辅助方法-------------------------------

        /// <summary>
        /// 检查手机号是否存在（已经存在抛出异常）
        /// </summary>
        /// <param name="PhoneNumber"></param>
        protected async void CheckForPhoneNumber(string PhoneNumber)
        {
            if (await this._userManager.IsExistPhoneNumberAsync(PhoneNumber))
            {
                throw new UserFriendlyException(string.Format("指定的手机号码已经被注册，请确认输入信息是否正确！"));
            }
        }

        /// <summary>
        /// 1. 注册新机构（每次注册都会创建一个Zhxt中的机构表）
        /// </summary>
        protected async Task<OEconomyOrgani> CreateOrganization(string plainPassword)
        {
            // 新的经济机构
            var orgEntity = EntityHelper.GetNewOEconomyOrgani();
            orgEntity.Id = _oeconomyOrganiManager.GetNewSequenceCode();
            // 创建一个管理员(并且更新一下经济机构的管理员账号)
            var adminEntity = EntityHelper.GetNewOEconomyAdmin(orgEntity, plainPassword);
            // 创建机构管理员
            await this._oeconomypersonManager.GenerateAdminAccount(adminEntity);
            orgEntity.GLYBH = adminEntity.Id;

            return await this._oeconomyOrganiManager.CreateAsync(orgEntity);
        }

        /* /// <summary>
         /// 创建机构管理员
         /// </summary>
         /// <returns></returns>
         protected async Task<OEconomyAdmin> CreateOEconomyAdmin(OEconomyOrgani OrganiEntity, string plainPassword)
         {
             // 创建一个管理员(并且更新一下经济机构的管理员账号)
             var entity = EntityHelper.GetNewOEconomyAdmin(OrganiEntity, plainPassword);
             return await this._oeconomypersonManager.GenerateAdminAccount(entity);
         }*/
        #endregion
    }
}
